package com.cz.run.task;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.cz.run.beans.mysql.*;
import com.cz.run.mapper.UserForceDao;
import com.cz.run.mapper.UserTradeRecordDao;
import com.cz.run.service.*;
import com.cz.run.utils.DateUtil;
import com.cz.run.utils.ForceUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author CAIYJ
 * @Description: 每日算力/积分计算
 * @Date:2018/6/5 16:07
 */
@Component
public class ForceTask {

    private static final Logger logger = LogManager.getLogger(ForceTask.class);

    private final Integer pageSize = 20;

    @Autowired
    private IUserForceCoefficientService userForceCoefficientService;

    @Autowired
    private IUserForceDynamicService userForceDynamicService;

    @Autowired
    private IUserBaseService userBaseService;

    @Autowired
    private IUserPointService userPointService;

    @Autowired
    private IUserForceService userForceService;

    @Autowired
    private IUserForceRecordService userForceRecordService;

    @Autowired
    private UserTradeRecordDao userTradeRecordDao;

    @Autowired
    private UserForceDao userForceDao;

    @Autowired
    private IPoolService poolService;

    @Autowired
    private IUserTradeRecordService userTradeRecordService;

    @Autowired
    private IForceStatisticsService forceStatisticsService;

    @Autowired
    private IUserPointFrozenService iUserPointFrozenService;

    @Scheduled(cron = "0 0 23 * * ? ")
    public void calPersonForce() throws Exception {
        logger.info("----------------------计算个人算力 START----------------------");
        long time = System.currentTimeMillis();
        EntityWrapper<UserBase> ew = new EntityWrapper<>();
        ew.where("`status` = {0}", 1);
        int count = userBaseService.selectCount(ew);
        if (count == 0) {
            return;
        }

        int loop = 0;
        Page<UserBase> page = null;
        int pageNum = count / pageSize;
        if (count % pageSize > 0) {
            pageNum++;
        }

        Set<Integer> ids = null;
        EntityWrapper<UserForceCoefficient> cew = null;
        List<UserForceCoefficient> userForceCoefficients = null;
        EntityWrapper<UserForceDynamic> dew = null;
        List<UserForceDynamic> userForceDynamics = null;
        EntityWrapper<UserForce> few = null;
        List<UserForce> userForces = null;
        List<UserForceRecord> userForceRecords = null;
        UserForceRecord userForceRecord = null;

        int stepNum = 0;
        double baseNum = 10D;
        double addNum = 1D;
        double tempNum = 0D;
        double personForce = 0D;

        // 分批次处理个人算力
        while (loop < pageNum) {
            page = new Page<>((loop + 1), pageSize);
            page = userBaseService.selectPage(page);
            ids = new HashSet<>();
            if (null != page && page.getRecords() != null && page.getRecords().size() > 0) {
                for (UserBase userBase : page.getRecords()) {
                    ids.add(userBase.getId());
                }
            }
            if (null == ids || ids.size() == 0) {
                continue;
            }

            cew = new EntityWrapper<>();
            cew.in("user_id", ids);
            userForceCoefficients = userForceCoefficientService.selectList(cew);
            dew = new EntityWrapper<>();
            dew.in("user_id", ids);
            dew.and("time", DateUtil.currentTimeMillisCN3(new Date()));
            userForceDynamics = userForceDynamicService.selectList(dew);
            few = new EntityWrapper<>();
            few.in("user_id", ids);
            userForces = userForceService.selectList(few);

            userForceRecords = new ArrayList<>();

            out:
            for (Integer id : ids) {
                if (null != userForces && userForces.size() > 0) {
                    for (UserForce userForce : userForces) {
                        if (id.equals(userForce.getUserId())) {
                            if (null != userForceCoefficients && userForceCoefficients.size() > 0) {
                                for (UserForceCoefficient userForceCoefficient : userForceCoefficients) {
                                    if (id.equals(userForceCoefficient.getUserId())) {
                                        baseNum = userForceCoefficient.getBaseForce();
                                        addNum = userForceCoefficient.getAddForce();
                                        break;
                                    }
                                }
                            }
                            if (null != userForceCoefficients && userForceCoefficients.size() > 0) {
                                for (UserForceDynamic userForceDynamic : userForceDynamics) {
                                    if (id.equals(userForceDynamic.getUserId())) {
                                        stepNum = userForceDynamic.getStep();
                                        tempNum = userForceDynamic.getTemp();
                                        break;
                                    }
                                }
                            }
                            personForce = ForceUtil.personForce(stepNum, baseNum, addNum, tempNum);
                            userForce.setForce((userForce.getForce() != null ? userForce.getForce() : 0D) + personForce);
                            userForceRecord = new UserForceRecord();
                            userForceRecord.setUserId(id);
                            userForceRecord.setForce(personForce);
                            userForceRecord.setTime(new Date());
                            userForceRecords.add(userForceRecord);
                            continue out;
                        }
                    }
                }
            }
            if (null != userForces && userForces.size() > 0) {
                userForceService.updateBatchById(userForces);
            }
            if (null != userForceRecords && userForceRecords.size() > 0) {
                userForceRecordService.insertBatch(userForceRecords);
            }
            loop++;
        }
        time = (System.currentTimeMillis() - time);
        logger.info("----------TIME:" + time + "ms----------");
        logger.info("----------------------计算个人算力 END----------------------");
    }

    @Scheduled(cron = "0 50 23 * * ? ")
    public void runPoint() throws Exception {
        logger.info("----------------------计算个人每日挖矿 START----------------------");
        long time = System.currentTimeMillis();
        double currency = 0D;

        // 获取旷池总币数
        EntityWrapper<Pool> pew = new EntityWrapper<>();
        pew.where("time = {0}", DateUtil.currentTimeMillisCN3(new Date()));
        Pool pool = poolService.selectOne(pew);
        if (null == pool) {
            pew = new EntityWrapper<>();
            pew.where("time = {0}", DateUtil.getDateAfterDayYYYYMMDD(new Date(), -1));
            pool = poolService.selectOne(pew);
            if (null != pool) {
                currency = pool.getCurrency();
                pool.setId(null);
                pool.setTime(new Date());
                poolService.insert(pool);
            }
        } else {
            currency = pool.getCurrency();
        }

        double totalForce = userForceDao.sumForce();

        Set<Integer> ids = null;
        EntityWrapper<UserPoint> upew = null;
        List<UserPoint> userPoints = null;
        List<UserTradeRecord> userTradeRecords = new ArrayList<>();
        UserTradeRecord userTradeRecord = null;

        // 每日算力转积分
        if (totalForce > 0 && currency > 0) {
            EntityWrapper<UserForce> ew = new EntityWrapper<>();
            int count = userForceService.selectCount(ew);
            if (count == 0) {
                return;
            }

            int loop = 0;
            Page<UserForce> page = null;
            int pageNum = count / pageSize;
            if (count % pageSize > 0) {
                pageNum++;
            }
            while (loop < pageNum) {
                page = new Page<>((loop + 1), pageSize);
                page = userForceService.selectPage(page);
                ids = new HashSet<>();
                if (null != page && page.getRecords() != null && page.getRecords().size() > 0) {
                    for (UserForce userForce : page.getRecords()) {
                        ids.add(userForce.getUserId());
                    }
                }
                if (null == ids || ids.size() == 0) {
                    continue;
                }
                upew = new EntityWrapper<>();
                upew.in("user_id", ids);
                userPoints = userPointService.selectList(upew);

                if (null != userPoints && userPoints.size() > 0) {
                    out:
                    for (UserPoint userPoint : userPoints) {
                        for (UserForce userForce : page.getRecords()) {
                            if (userPoint.getUserId().equals(userForce.getUserId())) {
                                double point = ForceUtil.miningPoint(currency, totalForce, userForce.getForce());
                                if("1".equals(pool.getType())){
                                    userPoint.setPointFrozen((userPoint.getPoint() != null ? userPoint.getPoint() : 0) + point);
                                    UserPointFrozen userPointFrozen = new UserPointFrozen();
                                    userPointFrozen.setFrom("自动挖矿");
                                    userPointFrozen.setPoint(point);
                                    userPointFrozen.setStatus(0);
                                    userPointFrozen.setTime(pool.getTimeFrozen());
                                    userPointFrozen.setUserId(userPoint.getUserId());
                                    iUserPointFrozenService.insert(userPointFrozen);
                                }else{
                                    userPoint.setPoint((userPoint.getPoint() != null ? userPoint.getPoint() : 0) + point);
                                }

                                userTradeRecord = new UserTradeRecord();
                                userTradeRecord.setUserId(userPoint.getUserId());
                                userTradeRecord.setType("5");
                                userTradeRecord.setPoint(point);
                                userTradeRecord.setTradeTime(new Date());
                                userTradeRecord.setAddress("system");
                                userTradeRecords.add(userTradeRecord);
                                continue out;
                            }
                        }
                    }
                }
                if (null != userPoints && userPoints.size() > 0) {
                    userPointService.updateBatchById(userPoints);
                }
                if (null != userTradeRecords && userTradeRecords.size() > 0) {
                    userTradeRecordService.insertBatch(userTradeRecords);
                }
                loop++;
            }
        }
        // 记录算力统计
        Double maxForce = userForceDao.maxForce();
        Double minForce = userForceDao.minForce();
        Double avgForce = userForceDao.avgForce();
        Double maxPoint = userTradeRecordDao.getMaxPointInDay(DateUtil.getDayStartTime(),DateUtil.getDayEndTime());
        ForceStatistics forceStatistics = new ForceStatistics();
        forceStatistics.setForceAvg(avgForce);
        forceStatistics.setForceMax(maxForce);
        forceStatistics.setForceMin(minForce);
        forceStatistics.setForceTotal(totalForce);
        forceStatistics.setPoolTotal(currency);
        forceStatistics.setTime(new Date());
        forceStatistics.setPointMax(maxPoint);
        forceStatisticsService.insert(forceStatistics);

        logger.info("----------TIME:" + time + "ms----------");
        logger.info("----------------------计算个人每日挖矿 END----------------------");
    }


    @Scheduled(cron = "0 0/10 * * * ? ")
    public void pointFrozen() throws Exception {
        EntityWrapper<UserPointFrozen> ew = new EntityWrapper<>();
        ew.where("status={0}","0");
        List<UserPointFrozen> list = iUserPointFrozenService.selectList(ew);
        List<UserPoint> userPoints = new ArrayList<>();
        List<UserPointFrozen> userPointFrozens = new ArrayList<>();

        for(UserPointFrozen param:list){
            if(param.getStatus()==0) {
                if (param.getTime().getTime() < System.currentTimeMillis()) {
                    EntityWrapper<UserPoint> uew = new EntityWrapper<>();
                    uew.where("user_id={0}", param.getUserId());
                    UserPoint userPoint = userPointService.selectOne(uew);
                    if (null != userPoint) {
                        userPoint.setPoint((userPoint.getPoint() != null ? userPoint.getPoint() : 0) + param.getPoint());
                        userPoint.setPointFrozen(userPoint.getPointFrozen() - param.getPoint());
                        userPoints.add(userPoint);
                    }
                    param.setStatus(0);
                    userPointFrozens.add(param);
                }
            }
        }

        if(null!=userPoints&&userPoints.size()>0)
        userPointService.updateBatchById(userPoints);

        if(null!=userPointFrozens&&userPointFrozens.size()>0)
        iUserPointFrozenService.updateBatchById(userPointFrozens);
    }
}
